package ua.kpi_java_training.zabrodskyi.module2;

/**
 * @author Maksym Zabrodskyi
 * @version 10-Jun-2013
 */
public class Predator extends Fish implements Move {

    private final int MAX_STEP_OF_MOVE = 4;
    private int randomStep;

    public Predator() {
        super();
    }

    public Predator(Position position) {
        super(position);
    }

    @Override
    public void move(Pool pool) {
        Position newPosition = new Position();
        newPosition.setPosition(this.getPosition());
        if (isPossibleMove(pool)) {
            chooseNewPosition(pool, newPosition);
        }
        this.setPosition(newPosition);
    }

    private boolean isPossibleMove(Pool pool) {
        int x = this.getPosition().getX();
        int y = this.getPosition().getY();
        randomStep = Random.getStep(MAX_STEP_OF_MOVE);
        boolean possibility = false;
        if (isFreeNewPosition(pool, x, y)
                || isSettleVictimInNewPosition(pool, x, y)) {
            possibility = true;
        }
        return possibility;
    }

    private boolean isFreeNewPosition(Pool pool, int x, int y) {
        return pool.isFreePosition(new Position(x - randomStep, y))
                || pool.isFreePosition(new Position(x + randomStep, y))
                || pool.isFreePosition(new Position(x, y - randomStep))
                || pool.isFreePosition(new Position(x, y + randomStep));
    }

    private boolean isSettleVictimInNewPosition(Pool pool, int x, int y) {
        return pool.isSettleObject(new Victim(),
                new Position(x - randomStep, y))
                || pool.isSettleObject(new Victim(),
                new Position(x + randomStep, y))
                || pool.isSettleObject(new Victim(),
                new Position(x, y - randomStep))
                || pool.isSettleObject(new Victim(),
                new Position(x, y + randomStep));
    }

    private void chooseNewPosition(Pool pool, Position newPosition) {
        if (isVictimInPool(pool)) {
            chooseNewPositionToNearestVictim(pool, newPosition);
        } else {
            chooseNewPositionInRandomDirection(pool, newPosition);
        }
    }

    private boolean isVictimInPool(Pool pool) {
        return pool.getNumberObjects(new Victim()) > 0;
    }

    private void chooseNewPositionToNearestVictim(Pool pool, Position newPosition) {
        do {
            newPosition.setPosition(this.getPosition());
            int x = newPosition.getX();
            int y = newPosition.getY();
            switch (whereNearestVictim(pool, newPosition)) {
                case LEFT:
                    newPosition.setX(x - randomStep);
                    break;
                case RIGHT:
                    newPosition.setX(x + randomStep);
                    break;
                case UP:
                    newPosition.setY(y - randomStep);
                    break;
                case DOWN:
                    newPosition.setY(y + randomStep);
                    break;
                default:
                    break;
            }
            if (pool.isBadPosition(newPosition)) {
                randomStep--;
            }
        } while (pool.isBadPosition(newPosition));
    }

    private Direction whereNearestVictim(Pool pool, Position newPosition) {
        return pool.whereNearestObject(new Victim(), newPosition);
    }

    private void chooseNewPositionInRandomDirection(Pool pool, Position newPosition) {
        do {
            newPosition.setPosition(this.getPosition());
            int x = newPosition.getX();
            int y = newPosition.getY();
            switch (Random.getDirection()) {
                case LEFT:
                    newPosition.setX(x - randomStep);
                    break;
                case RIGHT:
                    newPosition.setX(x + randomStep);
                    break;
                case UP:
                    newPosition.setY(y - randomStep);
                    break;
                case DOWN:
                    newPosition.setY(y + randomStep);
                    break;
                default:
                    break;
            }
        } while (pool.isBadPosition(newPosition));
    }

    @Override
    public void spawn(Pool pool) {
    }

    @Override
    public void eat(Pool pool) {
        if (isSettleVictim(pool, this.getPosition())) {
            new Victim(this.getPosition()).ruin(pool);
        }
    }

    private boolean isSettleVictim(Pool pool, Position position) {
        return pool.isSettleObject(new Victim(), position);
    }

    @Override
    public void ruin(Pool pool) {
    }

    @Override
    public boolean equals(Object object) {
        return (object instanceof Predator);
    }

    @Override
    public String toString() {
        return String.format("Predator is on position %s", super.getPosition());
    }

}
